//HashTable.cpp
#include "hashTable.h"
#include <stdio.h>

#include <string>
//---Container
Container::Container(unchar* _values, int _size, long _index)
{
	vector=new Vector(_values, _size);
	index=_index;
	next=NULL;
}
Container::~Container()
{
	delete vector;
}

//---HashItem
HashItem::HashItem(int value)
{
	link=NULL;
	hashValue=value;
}
HashItem::~HashItem()
{
	Container *temp=link;
	while(temp!=NULL)
	{
		link=temp->next;
		delete temp;
		temp=link;
	}
	link=NULL;
}
void HashItem::add(unchar* values, int size, long index)
{

	Container* temp = new Container(values, size, index);

	if(link!=NULL)
	{
		Container *last=link;
		for(;last->next!=NULL;)
			last=last->next;
		last->next=temp;
	}
	else
		link=temp;
}

//---HashTable
int HashTable::getHashCode(unchar* values, int size)
{
	int p, h=0, i=0;
	for(p=(int)values[0]; i<size; ++p)
	{
		h=multipier*h+p;
		++i;
	}
	return h%nHashes;
}

int HashTable::initTable(int size)
{
	if(limit!=0 || size<270)
		return 0;
	limit=size;
	createHashTable();
	return 1;
}
HashTable::HashTable()
{
	limit=0;
}
HashTable::HashTable(int size)
{
	initTable(size);
}
HashTable::~HashTable()
{
	deleteHashTable();
}
void HashTable::createHashTable()
{
	containersCounter=0;
	HashItem* temp;
	for(int i=0; i<(nHashes*2); ++i)
	{
		temp = new HashItem(i-nHashes);
		link[i]=temp;
	}
	resetHashTable();
}
void HashTable::deleteHashTable()
{
	for(int i=0; i<(nHashes*2); ++i)
	{
		delete link[i];
		link[i]=NULL;
	}
}
void HashTable::clear()
{
	deleteHashTable(); //TODO переписать это
	createHashTable();

}
int HashTable::add(unchar* values, int size)
{
	if(containersCounter>=limit)
	{
		//printf("\n!%d! table reseting",(int)containersCounter);
		//saveTable();
		//getchar();
		clear();
		return 0;
	}
	if((containersCounter>>_HowManyBitsToWrite)>0)
		++_HowManyBitsToWrite;
	HashItem *temp;
	temp=link[getHashCode(values, size)+nHashes];
	temp->add(values,size,containersCounter);
	++containersCounter;
	return 1;
}
int HashTable::contcmp(Container *link, unchar* values, int size)
{
	if(link->vector->getSize()!=size)
		return 0;
	for(int i=0; i<size;++i)
	{
		if(values[i]!=link->vector->getValues()[i])
			return 0;
	}
	return 1;
}
long HashTable::search(unchar* values, int size)
{
	HashItem *FirstCont;
	FirstCont=link[getHashCode(values, size)+nHashes];
	if(FirstCont->link==NULL)
		return -1;
	Container *temp;
	temp=FirstCont->link;
	for(;temp!=NULL;)
	{
		if(contcmp(temp, values, size))
			return temp->index;
		temp=temp->next;
	}
	return -1;

}
void HashTable::resetHashTable()
{
	unchar temp[256];
	containersCounter=0;
	int size=1;
	for(long i=0; i<257; ++i)
	{
		temp[i]=i;
		add(&temp[i], size);
	}
    _HowManyBitsToWrite=9;
}

void HashTable::saveTable()
{
	long count=0;
	FILE* file;
	Container *table[32000];

	Container* temp;

	for(int i=0;i<1000;++i)
	{
		temp=link[i]->link;
		for(;temp!=NULL;)
		{
			table[count]=temp;
			++count;
			temp=temp->next;
		}
	}

	for (int i=0; i < count; ++i)
	{
		for (int j=0; j < count-i-1; ++j)
		{
			if (table[j]->index > table[j+1]->index)
			{
				temp=table[j];
				table[j]=table[j+1];
				table[j+1]=temp;
			}
		}
	}
	static int countTS;
	countTS++;
	std::string name="log_HashTable";
	int tempy=countTS;
	for(int i=3;i>=0;--i)
	{
		if(i>0)
			tempy=(countTS)/(10*i);
		else
			tempy=countTS;
		name+=(char)(48+(tempy%10));
	}	
	name+=".txt";
	file=fopen(name.c_str(),"wb");
	if(!file)
		return;
	for (int i=0; i < count; ++i)
	{
		fprintf(file, "%d ",(int)table[i]->index);
		for(int j=0; j<table[i]->vector->getSize(); ++j)
		fprintf(file, "%c ",table[i]->vector->getValues()[j]);
		fprintf(file, " [");
		for(int j=0; j<table[i]->vector->getSize(); ++j)
			fprintf(file, "%d ",table[i]->vector->getValues()[j]);
		fprintf(file, "]\n");
	}
	fprintf(file, "\n%d ",(int)count);
	fclose(file);

}
